iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0
Modern Web

前端開發之那些我會的與我不會的技術系列 第 22

React的新實驗性Hook:use Hook的使用

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20231007/201627510x5ly9cTKv.jpg

今天要來接紹一個還在實驗性的hook,只有在實驗性和canary的版本才有支援。

這個hook的功能是用來讀取資源的值,這邊的資源可以是Promise和context兩種類型的資源。這個hook有一個跟其他hook不同的特點就是可以用在條件和迴圈裏面。

使用

const value = use(resource);

resource可以分為兩種Promise和context,先從較單純的context開始介紹

constext

用法和useContext雷同,useContext(SomeContext)變成use(SomeContext)回傳的一樣是context的值,不同的是use可以使用在條件和迴圈裡面,比useContext 用起來更靈活。

import { createContext, use } from "react";

export const TextContext = createContext();

function Content({name, show}) {
  if (show) {
    const val = use(TextContext); // 可以使用在條件裡
    return <>
      <h2>{val} {name}</h2>
    </>
  }
  return <h3>{name}</h3>

}

function ContentWrap({children}) {
  return <div>
    <h1>ContentWrap</h1>
     {children}
  </div>
}
function App() {
  return (
      <TextContext.Provider value={"哈囉"}>
        <ContentWrap>
          <Content show={true} name="小明" />
          <Content show={false} name="小美" />
        </ContentWrap>
      </TextContext.Provider>
  );
}
export default App;

Promise

這邊的use裡面接著一個fetch promise,然後搭配內建的Suspense元件使用。在use還在載入的時候會顯示fallback prop帶入的內容,等載入好就會顯示裡面的chidren,在下面這個範例就是Message元件。

  • resolve promise
function Message({ messagePromise }) {  
// 這個messagePromise就是fetchMessage return的fetch promise
const messageContent = use(messagePromise); 
  return <>
    <p>Here is the message:</p>
    <img src={messageContent} />
  </>
}

function MessageContainer({ messagePromise }) {
  return (
    <Suspense fallback={<p>⌛Downloading message...</p>}>
      <Message messagePromise={messagePromise} />
    </Suspense>
  );
}

function fetchMessage() {
  return fetch("https://dog.ceo/api/breeds/image/random") // 這邊找一個很可愛狗圖庫的api當範例
    .then((response) => response.json())
    .then((data) => data.message);
}

export default function App() {
  const [messagePromise, setMessagePromise] = useState(null);
  const [show, setShow] = useState(false);
  function download() {
    setMessagePromise(fetchMessage());
    setShow(true);
  }

  if (show) {
    return <MessageContainer messagePromise={messagePromise} />;
  } else {
    return <button onClick={download}>Download message</button>;
  }
}
  • rejected Promises

如果promise失敗可以用兩種方式處理

  1. promise catch

在fetch最後加上個catch

function fetchMessage() {
  return fetch("https://dog.ceo/api/breeds/image/random")
    .then((response) => response.json())
    .then((data) => data.message)
    .catch(() => {
      return "no new message found.";
    })
}

function Message({ messagePromise }) {
  const messageContent = use(messagePromise);
  console.log(messageContent);
// 畫面呈現可以加個小判斷
  return <>
    <p>Here is the message:</p>
    {
      messageContent.match(/^http/) 
        ? <img src={messageContent} alt="" />
        : messageContent
    }    
  </>
}
  1. 使用error boundary

可以直接使用**react-error-boundary不用自己寫class**

直接在最外層再包一層ErrorBoundary元件,將要顯示的錯誤畫面加入fallback屬性,可以看官網範例。我自己是用vite專案似乎會有與react版本會有些問題,無法使用。

export function MessageContainer({ messagePromise }) {
  return (
    <ErrorBoundary fallback={<p>⚠️Something went wrong</p>}>
      <Suspense fallback={<p>⌛Downloading message...</p>}>
        <Message messagePromise={messagePromise} />
      </Suspense>
    </ErrorBoundary>
  );
}

參考

https://react.dev/reference/react/use


上一篇
React Hook: useLayoutEffect的使用與注意事項
下一篇
React性能優化:利用useDeferredValue提升應用程式效能
系列文
前端開發之那些我會的與我不會的技術31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言